package org.xm.sk.controller.dbase;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.data.domain.Page;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.xm.sk.common.ToolsUtil;
import org.xm.sk.exception.DataNotFoundException;
import org.xm.sk.exception.RequestParamterException;
import org.xm.sk.service.data.BaseService;
import org.xm.sk.service.security.XmUser;
import org.xm.sk.vo.Base;
import org.xm.sk.vo.e.Datalevel;
import org.xm.sk.vo.ob.Ids;
import org.xm.sk.vo.ob.Local;
import org.xm.sk.vo.ob.LocalHairdresserList;
import org.xm.sk.vo.ob.LocalShopList;
import org.xm.sk.vo.ob.MapList;
import org.xm.sk.vo.ob.ModelShop;
import org.xm.sk.vo.ob.PageConf;
import org.xm.sk.vo.ob.ResultMsg;
import org.xm.sk.vo.ob.ShopInfo;
import org.xm.sk.vo.tb.Brand;
import org.xm.sk.vo.tb.Hairdresser;
import org.xm.sk.vo.tb.Image;
import org.xm.sk.vo.tb.Shop;
import org.xm.sk.vo.tb.User;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import springfox.documentation.annotations.ApiIgnore;

@SuppressWarnings("unchecked")
@Api(tags = { "shop" })
@RestController
@RequestMapping(value="/shops")
public class ShopController {
    
    @Autowired
    private MessageSource messages;
    @Autowired
    private BaseService<Brand> brandService;
    @Autowired
    private BaseService<Shop> shopService;
    @Autowired
    private BaseService<User> userService;
    @Autowired
    private BaseService<Image> imageService;
    
    @ApiOperation(value="创建门店", notes="根据shop对象创建门店，使用此接口需要ADMIN权限")
    @ApiImplicitParam(name = "shop", value = "门店详细实体shop", required = true, dataType = "Shop")
    @PreAuthorize("hasRole('ADMIN')")
    @RequestMapping(value="", method=RequestMethod.POST)
    public ResultMsg add(@RequestBody Shop shop) {
        Shop u = null;
        if (null == shop.getId() || 1 > shop.getId()) {
            u = new Shop();
        } else {
            u = (Shop) shopService.findById(shop.getId());
            if (!Base.isValid(u))
                u = new Shop();
        }
        if (null == u.getLatitude())
            u.setLatitude(23.360151);
        if (null == u.getLongitude())
            u.setLongitude(116.688462);
        u.setName(shop.getName());
        u.setBrand(null);
        if (null != shop.getBrandId() && 0 < shop.getBrandId()) {
            Brand b = (Brand) brandService.findById(shop.getBrandId());
            if (Base.isValid(b))
                u.setBrand(b);
        }
        u.setStarlevel(shop.getStarlevel());
        u.setPhone(shop.getPhone());
        u.setBusinessHours(shop.getBusinessHours());
        u.setAddress(shop.getAddress());
        u.getImages().clear();
        if (null != shop.getImageIds() && !shop.getImageIds().isEmpty()) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("findByIdIn", shop.getImageIds());
            Set<Image> sts = (Set<Image>) imageService.findAllByPage(null, map);
            u.getImages().addAll(sts);
        }
        if (null == u.getId())
            shopService.add(u);
        else
            shopService.update(u);
        return new ResultMsg("200", messages.getMessage("success", null, "SUCCESS", null), new Date());
    }

    @ApiIgnore()
    @ApiOperation(value="删除门店", notes="根据URI的id来指定删除对象")
    @ApiImplicitParam(name = "id", value = "门店ID", required = true, paramType = "path", dataType = "int")
    @RequestMapping(value="/{id}", method=RequestMethod.DELETE)
    public ResultMsg delete(@PathVariable Integer id) {
        shopService.delete(id);
        return new ResultMsg("200", messages.getMessage("success", null, "SUCCESS", null), new Date());
    }
    
    @ApiOperation(value="删除门店", notes="根据POST的id列表来指定删除对象，可批量")
    @ApiImplicitParam(name = "ids", value = "门店ID集", required = true, dataType = "Ids")
    @RequestMapping(value="/delete", method=RequestMethod.DELETE)
    public ResultMsg Batchdelete(@RequestBody Ids ids) {
        shopService.delete(ids.getIds());
        return new ResultMsg("200", messages.getMessage("success", null, "SUCCESS", null), new Date());
    }
    
    @ApiOperation(value="更新门店详细信息", notes="根据URI的id来指定更新对象，并根据传过来的shop信息来更新门店详细信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "门店ID", required = true, paramType = "path", dataType = "int"),
            @ApiImplicitParam(name = "shop", value = "待更新的门店详细实体shop", required = true, dataType = "Shop")
    })
    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
    public ResultMsg update(@PathVariable Integer id, @RequestBody Shop shop) throws DataNotFoundException {
        Shop u = (Shop) shopService.findById(id);
        if (null == u) {
            throw new DataNotFoundException(Shop.class.getName());
        }
        shop.setId(id);
        shop.setLatitude(23.360151);
        shop.setLongitude(116.688462);
        shopService.update(shop);
        return new ResultMsg("200", messages.getMessage("success", null, "SUCCESS", null), new Date());
    }

    @ApiOperation(value="获取门店详细信息", notes="根据URI的id来获取门店详细信息")
    @ApiImplicitParam(name = "id", value = "门店ID", required = true, paramType = "path", dataType = "int")
    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public Shop load(@PathVariable Integer id) throws DataNotFoundException {
        Shop u = (Shop) shopService.findById(id);
        if (null == u) {
            throw new DataNotFoundException(Shop.class.getName());
        }
        return u;
    }
    
    @ApiOperation(value="获取门店列表", notes="根据提交的分页信息列出所以门店信息")
    @ApiImplicitParam(name = "pageConf", value = "分页信息实体", required = true, dataType = "PageConf")
    @RequestMapping(value={"/list"}, method=RequestMethod.POST)
    public MapList<Shop> list(@RequestBody PageConf pageConf) {
        List<Shop> u = null;
        Long allCount = null;
        Object o = shopService.findAllByPage(pageConf);
        if (o instanceof Page) {
            allCount = ((Page<Shop>) o).getTotalElements();
            u = ((Page<Shop>) o).getContent();
        } else {
            allCount = (long) ((List<Shop>) o).size();
            u = (List<Shop>) o;
        }
        for (Shop c : u) {
            if (null != c.getBrand()) {
                c.setBrandId(c.getBrand().getId());
                c.setBrandName(c.getBrand().getName());
            }
            for (Image i : c.getImages()) {
                c.getImageIds().add(i.getId());
            }
            if (null != c.getFans() && !c.getFans().isEmpty())
                c.setFansCount(0L + c.getFans().size());
            else
                c.setFansCount(0L);
        }
        return new MapList<Shop>(allCount, u);
    }
    
    // --------------------- 业务具体接口 ---------------------
    
    @ApiOperation(value="（附近/搜索）门店列表", notes="根据提交的分页信息，以（门店名称为关键字搜索/位置信息为重点列出附近）门店信息，如果关键字不为空，优先以关键字搜索")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "size", value = "每页数量", required = true, paramType = "path", dataType = "int"),
        @ApiImplicitParam(name = "page", value = "页码", required = true, dataType = "int", paramType = "path"),
        @ApiImplicitParam(name = "local", value = "位置坐标信息", required = true, dataType = "Local")
    })
    @PreAuthorize("hasAnyRole('ADMIN', 'CLIENT')")
    @RequestMapping(value={"/{size}/{page}"}, method=RequestMethod.POST)
    public MapList<LocalShopList> list(@PathVariable Integer size,
            @PathVariable Integer page, @RequestBody Local local)
            throws RequestParamterException {
        if (null == size || null == page || 1 > size || 0 > page) {
            throw new RequestParamterException();
        }
        Page<ModelShop> shops = (Page<ModelShop>) shopService.findAllByPage(new PageConf(page, size), local);
        Long allCount = shops.getTotalElements();
        List<LocalShopList> result = new ArrayList<LocalShopList>();
        for (int i = 0; i < shops.getContent().size(); i++) {
            Shop shop = shops.getContent().get(i).getShop();
            shop.setDistance(shops.getContent().get(i).getDistance());
            LocalShopList sl = new LocalShopList();
            sl.setId(shop.getId());
            sl.setName(shop.getName());
            sl.setAddress(shop.getAddress());
            sl.setStarlevel(shop.getStarlevel());
            sl.setFansCount((long) shop.getFans().size());
            sl.setDistance(shop.getDistance());
            Set<Integer> ids = new HashSet<Integer>();
            for (Image image : shop.getImages()) {
                ids.add(image.getId());
            }
            sl.setImageIds(ids);
            XmUser xmUser = (XmUser) SecurityContextHolder.getContext()
                    .getAuthentication().getPrincipal();
            boolean isAt = false;
            Iterator<User> it = shop.getFans().iterator();
            while (it.hasNext()) {
                User user = it.next();
                if (new Integer(xmUser.getUserid()).equals(user.getId())) {
                    isAt = true;
                    break;
                }
            }
            sl.setIsAt(isAt);
            result.add(sl);
        }
        return new MapList<LocalShopList>(allCount, result);
    }

    @ApiOperation(value="关注门店", notes="根据URI的id来进行门店关注操作")
    @ApiImplicitParam(name = "id", value = "门店ID", required = true, paramType = "path", dataType = "int")
    @PreAuthorize("hasAnyRole('ADMIN', 'CLIENT')")
    @RequestMapping(value="/at/{id}", method=RequestMethod.GET)
    public ResultMsg at(@PathVariable Integer id) throws DataNotFoundException {
        Shop u = (Shop) shopService.findById(id);
        if (null == u) {
            throw new DataNotFoundException(Shop.class.getName());
        }
        XmUser xmUser = (XmUser) SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();
        User user = (User) userService.findById(xmUser.getUserid());
        if (null == user || Datalevel.NORMAL != user.getDatalevel()) {
            throw new AccessDeniedException("无效令牌信息，查无用户信息");
        }
        u.getFans().add(user);
        shopService.update(u);
        return new ResultMsg("200", "成功关注", new Date());
    }

    @ApiOperation(value="取消关注门店", notes="根据URI的id来进行取消关注门店操作")
    @ApiImplicitParam(name = "id", value = "门店ID", required = true, paramType = "path", dataType = "int")
    @PreAuthorize("hasAnyRole('ADMIN', 'CLIENT')")
    @RequestMapping(value="/ct/{id}", method=RequestMethod.GET)
    public ResultMsg ct(@PathVariable Integer id) throws DataNotFoundException {
        Shop u = (Shop) shopService.findById(id);
        if (null == u) {
            throw new DataNotFoundException(Shop.class.getName());
        }
        XmUser xmUser = (XmUser) SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();
        User user = (User) userService.findById(xmUser.getUserid());
        if (null == user || Datalevel.NORMAL != user.getDatalevel()) {
            throw new AccessDeniedException("无效令牌信息，查无用户信息");
        }
        u.getFans().remove(user);
        shopService.update(u);
        return new ResultMsg("200", "成功取消关注", new Date());
    }

    @ApiOperation(value="获取门店详细信息", notes="根据URI的id和提交的位置信息来获取门店详细信息，其中包括动态的距离信息")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "id", value = "门店ID", required = true, paramType = "path", dataType = "int"),
        @ApiImplicitParam(name = "local", value = "位置坐标信息", required = true, dataType = "Local")
    })
    @PreAuthorize("hasAnyRole('ADMIN', 'CLIENT')")
    @RequestMapping(value="/{id}", method=RequestMethod.POST)
    public ShopInfo load(@PathVariable Integer id, @RequestBody Local local)
            throws DataNotFoundException {
        Shop u = (Shop) shopService.findById(id);
        if (null == u) {
            throw new DataNotFoundException(Shop.class.getName());
        }
        ShopInfo shopInfo = new ShopInfo();
        Double distance = ToolsUtil.distance(local,
                new Local(u.getLatitude(), u.getLongitude(), null, null));
        shopInfo.setId(u.getId());
        shopInfo.setName(u.getName());
        shopInfo.setAddress(u.getAddress());
        shopInfo.setStarlevel(u.getStarlevel());
        shopInfo.setFansCount((long) u.getFans().size());
        shopInfo.setDistance(distance);
        Set<Integer> ids = new HashSet<Integer>();
        for (Image image : u.getImages()) {
            ids.add(image.getId());
        }
        shopInfo.setImageIds(ids);
        XmUser xmUser = (XmUser) SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();
        boolean isAt = false;
        Iterator<User> it = u.getFans().iterator();
        while (it.hasNext()) {
            User user = it.next();
            if (new Integer(xmUser.getUserid()).equals(user.getId())) {
                isAt = true;
                break;
            }
        }
        shopInfo.setIsAt(isAt);
        shopInfo.setBusinessHours(u.getBusinessHours());
        shopInfo.setPhone(u.getPhone());
        Set<LocalHairdresserList> lhl = new HashSet<LocalHairdresserList>();
        Iterator<Hairdresser> hairdressers = u.getHairdressers().iterator();
        while (hairdressers.hasNext()) {
            Hairdresser hairdresser = hairdressers.next();
            LocalHairdresserList lh = new LocalHairdresserList();
            lh.setId(hairdresser.getId());
            lh.setName(hairdresser.getName());
            lh.setFansCount(hairdresser.getFans().size());
            lh.setCmark(hairdresser.getCmark());
            if (null != hairdresser.getShop())
                lh.setShopName(hairdresser.getShop().getName());
            if (null != hairdresser.getUser()
                    && null != hairdresser.getUser().getImage())
                lh.setImageId(hairdresser.getUser().getImage().getId());
            isAt = false;
            it = hairdresser.getFans().iterator();
            while (it.hasNext()) {
                User user = it.next();
                if (new Integer(xmUser.getUserid()).equals(user.getId())) {
                    isAt = true;
                    break;
                }
            }
            lh.setIsAt(isAt);
            lhl.add(lh);
        }
        shopInfo.setHairdresser(lhl);
        return shopInfo;
    }
    
    @ApiOperation(value="获取关注的门店列表", notes="此接口只允许管理员和客户调用，返回用户关注的门店列表信息")
    @ApiImplicitParam(name = "pageConf", value = "分页信息实体", required = true, dataType = "PageConf")
    @PreAuthorize("hasAnyRole('ADMIN', 'CLIENT')")
    @RequestMapping(value="/at/list", method=RequestMethod.POST)
    public MapList<LocalShopList> atList(@RequestBody PageConf pageConf) throws DataNotFoundException {
        XmUser xmUser = (XmUser) SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("userid", xmUser.getUserid());
        Page<LocalShopList> u = (Page<LocalShopList>) shopService.findAllByPage(pageConf, map);
        Long allCount = u.getTotalElements();
        return new MapList<LocalShopList>(allCount, u.getContent());
    }
    
}
